﻿
Imports System.Net.Sockets
Imports tcpTrans

Namespace tcpTrans4
    Public Module tcpTrans4
        Private ReadOnly TCPTRANS4_SEND_TICKS As Int64
        Private ReadOnly TCPTRANS4_SEND_BYTES As Int64
        Private ReadOnly TCPTRANS4_RECEIVE_DATASIZEPREFIX_TICKS As Int64
        Private ReadOnly TCPTRANS4_RECEIVE_TICKS As Int64
        Private ReadOnly TCPTRANS4_RECEIVE_BYTES As Int64
        Private ReadOnly TCPTRANS4_PACKAGE_SIZE As Int64
        Private ReadOnly TRACE_DETAIL As Boolean

        Public Function send(ByVal tcpClient As TcpClient,
                             ByVal data As nettransData,
                             ByVal holdtime As Int64,
                             Optional ByRef ec As eventComb = Nothing,
                             Optional ByVal legacyDataSize As Boolean = False) As Boolean
            Dim buff() As Byte = Nothing
            Dim size As Int64 = 0
            Dim init As ternary = Nothing
            Dim stream As NetworkStream = Nothing
            init = initial_send(tcpClient, stream, holdtime, data, buff, size, legacyDataSize)
            If init.notunknown() Then
                Return init.true_()
            End If

            Dim startTimeTicks As Int64 = 0
            startTimeTicks = Now.ticks()
            Dim writeec As eventComb = Nothing
            If writestream4(stream, buff, size, ticksToMilliseconds(startTimeTicks), holdtime, writeec) Then
                ec = New eventComb(Function() As Boolean
                                       Return waitfor(writeec) AndAlso
                                              [goto](1)
                                   End Function,
                                   Function() As Boolean
                                       Return eventComb.success_behavior(
                                                  writeec,
                                                  Sub()
                                                      counter.increase(TCPTRANS4_PACKAGE_SIZE, size)
                                                      counter.increase(TCPTRANS4_SEND_BYTES, size)
                                                      If TRACE_DETAIL Then
                                                          counter.recordTimeTicks(TCPTRANS4_SEND_TICKS, startTimeTicks)
                                                      End If
                                                      goto_end()
                                                  End Sub)
                                   End Function)
                Return True
            Else
                raiseError(errorHandle.displayMode.console, "failed to start sending data to " + _
                           remoteEndPoint(tcpClient), errorHandle.errorType.exclamation)
                [erase](buff)
                Return False
            End If
        End Function

        Public Function receive(ByVal tcpClient As TcpClient,
                                ByRef data As nettransData,
                                ByVal holdtime As Int64,
                                Optional ByVal needOvertimeOrNotConnectedInfo As Boolean = True,
                                Optional ByVal needClearData As Boolean = True,
                                Optional ByRef ec As eventComb = Nothing,
                                Optional ByVal legacyDataSize As Boolean = False)
            Dim init As ternary = Nothing
            Dim stream As NetworkStream = Nothing
            init = initial_receive(tcpClient, stream, holdtime, data, needOvertimeOrNotConnectedInfo, needClearData)
            If init.notunknown() Then
                Return init.true_()
            End If

            Dim d As nettransData = Nothing
            d = data
            Dim rst As pointer(Of bytes) = Nothing
            rst = New pointer(Of bytes)()
            Dim dataLength As Int64
            Dim rtn As Boolean = False
            Dim starttimeTicks As Int64 = 0

            Dim readec As eventComb = Nothing
            ec = New eventComb(Function() As Boolean
                                   Return eva(starttimeTicks, Now.ticks()) AndAlso
                                          readstream4(stream,
                                                      length:=dataSizePrefixLength,
                                                      starttime:=ticksToMilliseconds(starttimeTicks),
                                                      holdtime:=holdtime,
                                                      ec:=readec,
                                                      result:=rst) AndAlso
                                          waitfor(readec) AndAlso
                                          goto_next()
                               End Function,
                               Function() As Boolean
                                   Dim failureAction As void =
                                            Sub()
                                                If TRACE_DETAIL Then
                                                    raiseError(errorHandle.displayMode.console,
                                                               "cannot get head information, skip receiving from " +
                                                                remoteEndPoint(tcpClient),
                                                                errorHandle.errorType.exclamation)
                                                End If
                                                goto_end()
                                            End Sub
                                   Return eventComb.success_behavior(
                                              readec,
                                              Function() As Boolean
                                                  If tcpTrans.dataLength(+rst, dataLength, legacyDataSize) Then
                                                      If TRACE_DETAIL Then
                                                          counter.recordTimeTicks(
                                                              TCPTRANS4_RECEIVE_DATASIZEPREFIX_TICKS,
                                                              starttimeTicks)
                                                      End If
                                                      Return readstream4(stream,
                                                                         length:=dataLength,
                                                                         ec:=readec,
                                                                         result:=rst) AndAlso
                                                             waitfor(readec) AndAlso
                                                             goto_next()
                                                  Else
                                                      failureAction()
                                                      Return False
                                                  End If
                                              End Function,
                                              failureAction)
                               End Function,
                               Function() As Boolean
                                   Return eventComb.success_behavior(
                                              readec,
                                              Sub()
                                                  Dim totalSize As Int64 = 0
                                                  totalSize = dataLength + dataSizePrefixLength
                                                  counter.increase(TCPTRANS4_PACKAGE_SIZE, totalSize)
                                                  counter.increase(TCPTRANS4_RECEIVE_BYTES, totalSize)
                                                  If TRACE_DETAIL Then
                                                      counter.recordTimeTicks(TCPTRANS4_RECEIVE_TICKS, starttimeTicks)
                                                  End If
                                                  assert((+rst).size() = dataLength)
                                                  d.import(++rst, 0, dataLength)
                                                  rtn = True
                                                  goto_end()
                                              End Sub,
                                              Sub()
                                                  raiseError(errorHandle.displayMode.console,
                                                             "failed to receive data from " +
                                                             remoteEndPoint(tcpClient),
                                                             errorHandle.errorType.exclamation)
                                              End Sub)
                               End Function)
            Return True
        End Function

        Sub New()
            TRACE_DETAIL = envs.nettrace() OrElse isdebugmode()
            If TRACE_DETAIL Then
                TCPTRANS4_RECEIVE_DATASIZEPREFIX_TICKS =
                    counter.registerAverageAndLastAverage("TCPTRANS4_RECEIVE_DATASIZEPREFIX_TICKS")
                TCPTRANS4_RECEIVE_TICKS = counter.registerAverageAndLastAverage("TCPTRANS4_RECEIVE_TICKS")
                TCPTRANS4_SEND_TICKS = counter.registerAverageAndLastAverage("TCPTRANS4_SEND_TICKS")
            End If
            TCPTRANS4_RECEIVE_BYTES = counter.registerRateAndLastRate("TCPTRANS4_RECEIVE_BYTES")
            TCPTRANS4_SEND_BYTES = counter.registerRateAndLastRate("TCPTRANS4_SEND_BYTES")
            TCPTRANS4_PACKAGE_SIZE = counter.registerAverageAndLastAverage("TCPTRANS4_PACKAGE_SIZE")
        End Sub
    End Module
End Namespace
